package com.yjd.comm.fundservice.util;

import com.alibaba.fastjson.JSON;
import com.yjd.comm.encrypt.AesUtil;
import com.yjd.comm.encrypt.EncryptTool;
import com.yjd.comm.encrypt.RsaUtil;
import com.yjd.comm.fundservice.dto.QKConfig;
import com.yjd.comm.fundservice.dto.QKResponse;
import com.yjd.comm.fundservice.dto.QkCallBackMsgDto;
import com.yjd.comm.fundservice.enums.BusTypeEnum;
import com.yjd.comm.fundservice.enums.FundChannelEnum;
import com.yjd.comm.fundservice.model.FundCalbackLogsModel;
import com.yjd.comm.fundservice.model.FundServiceLogModel;
import com.yjd.comm.fundservice.service.IFundCalbackLogsService;
import com.yjd.comm.fundservice.service.IFundServiceLogService;
import com.yjd.comm.system.util.SysParamUtil;
import com.yjd.comm.util.FrameUtil;
import com.yjd.comm.util.HttpsUtil;
import com.yjd.comm.util.ServiceHolder;
import com.yjd.comm.util.StringUtil;
import com.yjd.comm.vo.Constant;
import org.apache.log4j.Logger;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by yjd-wap on 2018/1/21.
 */
public class QianKangServerUtil {

    private static Logger logger = Logger.getLogger(QianKangServerUtil.class);

    /**
     *  获取资金配置信息
     * @return
     * @throws Exception
     */
    private static QKConfig getQKFundConfig()throws Exception{
        QKConfig qkConfig = StringUtil.getObject(SysParamUtil.getValue(Constant.SysParamKeyEnum.QK_FUND_CONFIG),QKConfig.class);
        Assert.notNull(qkConfig, "第三方配置信息缺失");
        return qkConfig;
    }

    public static String getQKFundApplyCallbackUrl()throws Exception{
        return getQKFundConfig().getCall_back();
    }

    private static IFundServiceLogService getFundServiceLogService() {
        return ServiceHolder.getLocalService(IFundServiceLogService.class, "fundServiceLogService");
    }

    private static IFundCalbackLogsService getFundCalbackLogsService() {
        return ServiceHolder.getLocalService(IFundCalbackLogsService.class, "fundCalbackLogsService");
    }

    public static <T extends Object> T sendMsgTest(QKConfig qkConfig,Object obj,String bus_url,BusTypeEnum busTypeEnum,String bus_id, Class<T> cs)throws Exception {
        Long start_time = 0l;
        Long end_time = 0l;
        String ask_content = "";
        String bus_data = "";
        String return_msg = "";
        try {
            if (qkConfig == null || StringUtil.isEmpty(qkConfig.getServer_url()) || StringUtil.isEmpty(qkConfig.getMy_private_key()) || StringUtil.isEmpty(qkConfig.getQk_public_key())) {
                FrameUtil.throwBaseException1("接口配置参数异常！");
            }
            if (obj == null) {
                FrameUtil.throwBaseException1("请求业务数据不能为空");
            }

            if (StringUtil.isEmpty(bus_url)) {
                FrameUtil.throwBaseException1("请求url不能为空");
            }

            String url = qkConfig.getServer_url() + bus_url;
            String v1 = EncryptTool.generateRandom32();
            String v2 = EncryptTool.generateRandom16();
            bus_data = busDataHandle(StringUtil.objectToMap(obj), qkConfig);//封装业务数据
            ask_content = busDataEncrypt(v1,v2,bus_data,qkConfig.getQk_public_key());//加密封装的业务数据
            start_time = System.currentTimeMillis();
            HttpsUtil.HttpResponseWrapper response = HttpsUtil.requestPostData(url,ask_content,HttpsUtil.APPLICATION_JSON,HttpsUtil.CHARACTER_ENCODING);
            end_time = System.currentTimeMillis();
            return_msg = response.getResponseString(HttpsUtil.CHARACTER_ENCODING);
            // 将响应数据的data信息转换为cs对象数据
            return QianKangServerUtil.parseResponse(v1,v2,return_msg, cs);

        } catch (Exception e) {
            logger.error("资金服务异常：" + e);
            throw e;
        }
    }

    public static <T extends Object> T sendMsg(Object obj,BusTypeEnum busTypeEnum,String bus_id, Class<T> cs)throws Exception {
        long start_time = 0l;
        long end_time = 0l;
        T response_obj = null;
        String bus_data = "";
        String ask_content = "";
        String return_msg = "";

        QKConfig qkConfig = getQKFundConfig();
        if (qkConfig == null || StringUtil.isEmpty(qkConfig.getServer_url()) || StringUtil.isEmpty(qkConfig.getMy_private_key()) || StringUtil.isEmpty(qkConfig.getQk_public_key())) {
            FrameUtil.throwBaseException1("接口配置参数异常！");
        }
        if (obj == null) {
            FrameUtil.throwBaseException1("请求业务数据不能为空");
        }
        if (busTypeEnum==null) {
            FrameUtil.throwBaseException1("请求url不能为空");
        }

        try {
            String url = qkConfig.getServer_url() + busTypeEnum.getUrl();
            String v1 = EncryptTool.generateRandom32();
            String v2 = EncryptTool.generateRandom16();
            bus_data = busDataHandle(StringUtil.objectToMap(obj), qkConfig);//封装业务数据
            ask_content = busDataEncrypt(v1,v2,bus_data,qkConfig.getQk_public_key());//加密封装的业务数据
            start_time = System.currentTimeMillis();
            HttpsUtil.HttpResponseWrapper response = HttpsUtil.requestPostData(url,ask_content,HttpsUtil.APPLICATION_JSON,HttpsUtil.CHARACTER_ENCODING);
            end_time = System.currentTimeMillis();
            return_msg = response.getResponseString(HttpsUtil.CHARACTER_ENCODING);
            // 将响应数据的data信息转换为cs对象数据
            response_obj = QianKangServerUtil.parseResponse(v1,v2,return_msg, cs);
            return  response_obj;

        }catch (Exception e) {
            logger.error("贷款申请服务异常,返回信息："+return_msg+"异常信息:" + e);
            throw e;
        } finally {
            //记录资金服务请求日志
            insertLog(FundChannelEnum.QIAN_KANG.getValue(), start_time, end_time, busTypeEnum, bus_id, bus_data, response_obj==null?"":JSON.toJSONString(response_obj));
        }

    }

    private static void insertLog(Integer fund_channel, long start_time, long end_time, BusTypeEnum bus_type,String bus_id, String ask_content,
                                 String return_msg){
        try {
            getFundServiceLogService().insert(new FundServiceLogModel(fund_channel,start_time,end_time,bus_type,bus_id,ask_content,return_msg,FrameUtil.getTime()));
        }catch (Exception e){
            logger.error("资金服务插入日期服务异常："+e);
        }
    }

    public static String busDataHandle(Map param,QKConfig qkConfig)throws Exception{
        param.put("agent_id", qkConfig.getAgent_id());
        String v3 = AesUtil.sortMapByKey(param);//对数据进行排序
        String v4 = EncryptTool.HMACSHA256Encode(qkConfig.getAgent_secret(), v3); //签名数据
        param.put("sign",v4);
       return JSON.toJSONString(param);//生成json格式数据
    }

    /**
     * 数据加密
     * @param v1 16位AES加密向量
     * @param v2 32位AES加密key
     * @return
     * @throws Exception
     */
    public static String busDataEncrypt(String v1,String v2,String v3,String public_key)throws Exception{
        String v4 = AesUtil.encryptByCBC(v3,v1,v2);//base64加密
        String v5 = RsaUtil.encryptByRsaPub(v1,public_key);//加密后秘钥
        Map request = new HashMap();
        request.put("data",v4);
        request.put("sc",v5);
        request.put("iv",v2);
        return  JSON.toJSONString(request);
    }

    /**
     * 解析返回结果
     * @param return_msg 返回信息
     * @param cs 返回信息类型
     * @return
     * @throws Exception
     */
    private static <T extends Object> T parseResponse(String v1,String v2,String return_msg, Class<T> cs)throws Exception{
        String msg = AesUtil.decryptByCBC(return_msg,v1,v2);
        Assert.hasLength(msg, "获取不到返回信息，请联系第三方相关人员。");
        QKResponse response = StringUtil.getObject(msg,QKResponse.class);
        Assert.notNull(response, "返回信息为空");
        // 响应码，0：成功，其他为异常
        if(response.getCode() > 0 && response.getCode() != 2004){
            logger.error("第三方处理失败，原因：" + msg);
            FrameUtil.throwBaseException1(response.getMessage());
        }
        T to = StringUtil.getObject(response.getData(), cs);
        Assert.notNull(to, "第三方返回数据为空");
        return to;
    }

    /**
     *  解析数据
     * @param data base64数据
     * @param iv 16位明文向量
     * @return
     * @throws Exception
     */
    private static String parseData(String v1,String data,String iv,String agent_secret)throws Exception{
        String v2 = AesUtil.decryptByCBC(data,v1,iv);//通过秘钥和向量解密
        Map paseMap = StringUtil.getObject(v2,Map.class);
        String v3 = paseMap.get("sign").toString();
        paseMap.remove("sign");
        String v4 = AesUtil.sortMapByKey(paseMap);//明文排序
        String v5 = EncryptTool.HMACSHA256Encode(agent_secret,v4);//加密明文
        if(!v3.equals(v5)){
            FrameUtil.throwBaseException1("接口响应的数据不合法");
        }
        paseMap.put("sign",v3);
      return  JSON.toJSONString(paseMap);
    }

    /**
     * 所有回调的方法都调用此方法进行数据解析
     * @param callbackurl 回调的url
     * @param callBackMsgDto 回调接口返回的信息
     * @param cs
     * @return
     * @throws Exception
     */
    public static <T extends Object> T parseCallbackResponse(String key,String callbackurl, QkCallBackMsgDto callBackMsgDto, Class<T> cs)throws Exception{
        T result = null;
        String msg ="";
        try {
            msg = parseData(key,callBackMsgDto.getData(),callBackMsgDto.getIv(),getQKFundConfig().getAgent_secret());//明文信息
            Assert.notNull(msg, "第三方回调数据为空");
            return  StringUtil.getObject(msg, cs);
        }catch (Exception e){
            logger.error(e);
        }finally {
            getFundCalbackLogsService().insert(new FundCalbackLogsModel(1,callbackurl,msg,FrameUtil.getTime()));
        }
        return result;
    }

    public static String getKeyPlainText(String sc)throws Exception{
        if(StringUtil.isEmpty(sc)){
            return "";
        }
       return RsaUtil.decryptByRsaPri(sc,getQKFundConfig().getMy_private_key());
    }


}
